﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;


namespace terav_totris
{   
    /// <summary>
    /// Määrab Space Totrise mängu toimimise loogika
    /// </summary>
    class Loogika
    {
        // Kontroll, kas mäng on läbi või pausil
        private bool manguOts;
        private bool manguPaus;             
        
        // Ajamuutujad
        private const float ALGNE_MAKSIMUM_AEG= 1.0f;
        private const float AJA_VAHENDAJA= 0.1f;
        private float ajaHoidja;
        private float aegLiigutamiseks;

#region saaAnna
        public bool ManguOts
        {
            get { return manguOts; }
            set { manguOts = value; }
        }

        public bool ManguPaus
        {
            get { return manguPaus; }
            set { manguPaus = value; }
        }

#endregion

        /// <summary>
        /// Konstruktor. Määrab, et avamisel mäng ei ole veel käivitunud,
        /// paneb ajutise ajaloenduri "ajaHoidja" nulli ning määrab, mis
        /// aja tagant kujundit edasi nihutatakse (aegLiigutamiseks). 
        /// </summary>
        public Loogika()
        {
            manguOts = true;
            manguPaus = false; 
                      
            ajaHoidja = 0f;
            aegLiigutamiseks = ALGNE_MAKSIMUM_AEG;           
        }

        /// <summary>
        /// Meetod mõõdab aega (ajaHoidja) ja kui see jõuab ühe sekundini (aegLiigutamiseks),
        /// läheb ajamõõdik jälle nulli ning kujund liigub ühe tulba võrra paremale.
        /// Kui kujund jõuab väljaku serva või teise kujundini,
        /// kinnitatakse ta sinna paika.
        /// </summary>
        /// <param name="manguAeg">mänguaja loendur</param>
        /// <param name="tase">mängutase, millest sõltub väljaku laius</param>
        /// <param name="kujund">mängusolev kujund</param>
        public void UusAeg(GameTime manguAeg, Tase tase, Kujund kujund)
        {
            //kui mängul ei ole pausi peal, siis uuendatakse aega, muidu mäng seisab
            if (!manguPaus)
            {
                ajaHoidja += (float)manguAeg.ElapsedGameTime.TotalSeconds;

                if (ajaHoidja >= aegLiigutamiseks)
                {
                    ajaHoidja = 0f;
                    kujund.KokkuporgeteAvastamine(tase);

                    if (kujund.ParemKokkuPorge)
                    {
                        KlotsPaika(tase, kujund);
                    }
                    else
                    {
                        kujund.AsuKohaTulp += 1;
                    }
                } 
            }
            
        }

        /// <summary>
        /// "Salvestab" väljaku serva või teiste kujunditeni välja jõudnud kujundi
        /// väljakule. Ühtlasi laseb kontrollida, kas mõni tulp sai täis, laseb valmis
        /// panna uue kujundi ja kontrollida, kas uut kujundit mahub väljakule joonistama
        /// </summary>
        /// <param name="tase">Mängutase, millest sõltub väljaku laius</param>
        /// <param name="kujund">Kujund, mida paika pannakse</param>
        private void KlotsPaika(Tase tase, Kujund kujund) 
        {           
            // Jätab paremasse väljaku serva jõudnud kujundi mänguväljakule
            kujund.JataKujundPaika(tase);

            //tase.TegeleTaisTulbaga();

            // Järgmine kujund joonistatakse väljakule
            kujund.JargmineValmis();

            // Kontrollitakse, kas järgmist kujundit mahub väljakule joonistada
            ManguLopuKontroll(tase, kujund);
        }

        /// <summary>
        /// See meetod kontrollib, kas uus kujund mahub väljakule ära. Kui ei, siis
        /// on mäng läbi
        /// </summary>
        /// <param name="tase">Eraldi klassis kirjeldatud mängutase, mis määrab väljaku laiuse</param>
        /// <param name="kujund">Kujund, mille mahtumist väljakule kontrollitakse</param>     
        private void ManguLopuKontroll(Tase tase, Kujund kujund)
        {
            for (int rida = 0; rida < 4; rida++)
                for (int tulp = 0; tulp < 4; tulp++)
                    if (Kujund.andmed[kujund.Liik, kujund.Asend, rida, tulp] == 1)
                        if (tase.Valjak[kujund.AsuKohaTulp + tulp, kujund.AsuKohaRida + rida] != -1)
                        {
                            manguOts = true;
                            if (!Totris.Taust.IsPaused)
                            {
                                Totris.sfxHeli.PlayCue("no"); // Mängu lõpu heliefekt
                                Totris.Taust.Pause();
                            }
                        }
            
        }

        /// <summary>
        /// Meetodit kasutatakse nii algpildi kui mängu käigus kuvatava
        /// taustapildi ettemanamiseks.
        /// </summary>
        /// <param name="tekstuur">taustatekstuur</param>
        /// <param name="spriteBatch">joonistav spritebatch</param>
        public void JoonistaTaust(Texture2D tekstuur, SpriteBatch spriteBatch)
        {
            spriteBatch.Begin();
            spriteBatch.Draw(tekstuur, Vector2.Zero, Color.White);
            spriteBatch.End();
        }
 

        /// <summary>
        /// See meetod kamandab P-klahvi. Kui mäng on läbi, siis P-klahvi vajutamine
        /// põhjustab uue mängu alustamise. Kui mäng on pooleli, siis P-klahvi vajutus 
        /// tähendab, et mängija tahab teha pausi või seda katkestada
        /// </summary>
        /// <param name="klaveriOlek">klaviatuuri hetkeolek</param>
        /// <param name="eelmineOlek">klaviatuuri eelmine olek</param>
        /// <param name="tase">mängutase, millest sõltub väljaku laius</param>
        /// <param name="kujund">kujund, mis mängu pihtahakkamisel väljakule tuleb</param>
        public void KontrolliManguPausi(KeyboardState klaveriOlek, KeyboardState eelmineOlek, Tase tase, Kujund kujund)
        {               
            if (klaveriOlek.IsKeyDown(Keys.P) && !eelmineOlek.IsKeyDown(Keys.P))
            {
                if (manguOts)
                {
                    AlgvaartustaUusMang(tase, kujund);
                }
                else
                {
                    manguPaus = !manguPaus;
                }
            }

            // Kui Esc-nuppu muljuda, siis mäng lõpeb ja alguspilt tuleb ette
            if (klaveriOlek.IsKeyDown(Keys.Escape))
                manguOts = true;

            // Uue mängu alustamine
            if (klaveriOlek.IsKeyDown(Keys.R))
                AlgvaartustaUusMang(tase, kujund);
        }        


        /// <summary>
        /// See meetod kamandab Start nuppu. Kui mäng on läbi, siis Start nupu vajutamine
        /// põhjustab uue mängu alustamise. Kui mäng on pooleli, siis Start nupu vajutus 
        /// tähendab, et mängija tahab teha pausi või seda katkestada
        /// </summary>
        /// <param name="puldiOlek">puldi hetkeolek</param>
        /// <param name="puldiEelmineOlek">puldi eelmine olek</param>
        /// <param name="tase">mängutase, millest sõltub väljaku laius</param>
        /// <param name="kujund">kujund, mis mängu pihtahakkamisel väljakule tuleb</param>
        public void KontrolliManguPausi(GamePadState puldiOlek, GamePadState puldiEelmineOlek, Tase tase, Kujund kujund)
        {
            if (puldiOlek.Buttons.Start == ButtonState.Pressed && puldiEelmineOlek.Buttons.Start == ButtonState.Released)
            {
                if (manguOts)
                {
                    AlgvaartustaUusMang(tase, kujund);
                }
                else
                {
                    manguPaus = !manguPaus;
                }
            }

            // Back-nupp lõpetab mängu
            if (puldiOlek.Buttons.Back == ButtonState.Pressed && puldiEelmineOlek.Buttons.Back == ButtonState.Released)
                manguOts = true;

            // X-nupp alustab uut mängu
            if (puldiOlek.Buttons.X == ButtonState.Pressed && puldiEelmineOlek.Buttons.Back == ButtonState.Released)
                AlgvaartustaUusMang(tase, kujund);
        }     



        /// <summary>
        /// Avab uue mängu, annab algväärtused
        /// </summary>
        /// <param name="tase">Mängutase, mis määrab väljakusuuruse ja mänguarvestuse</param>
        /// <param name="kujund">Mängu avav uus kujund</param>
        private void AlgvaartustaUusMang(Tase tase, Kujund kujund)
        {            
            manguOts= false;
            manguPaus = false;
            tase.manguRidu = 0;
            tase.manguSkoor = 0;
            tase.manguTase = 0;

            ajaHoidja = 0f;
            aegLiigutamiseks = ALGNE_MAKSIMUM_AEG;
                        
            tase.algValjak();
            kujund.TekitaKujund();
            if (Totris.Taust.IsPaused)
                Totris.Taust.Resume();
        }

        /// <summary>
        /// Hangib sisendi klaviatuurikasutajalt, vaatab, kas see käsk on võimalik, ja viib käsu ellu
        /// </summary>
        
        public void LiigutaKujund(KeyboardState klaveriOlek, KeyboardState eelmineOlek, Tase tase, Kujund kujund)
        {
           
            // Kõigepealt üritatakse avastada kokkupõrkeid, et teha kindlaks, milliseid klahve on üldse võimalik kasutada
            kujund.KokkuporgeteAvastamine(tase);

            // Parem nool liigutab klahvi ühe tulba võrra edasi
            if (klaveriOlek.IsKeyDown(Keys.Right) && !eelmineOlek.IsKeyDown(Keys.Right) 
                && !kujund.ParemKokkuPorge)
            {
                kujund.AsuKohaTulp += 1; 
            }

            // Vasak nool pöörab klotsi
            if (klaveriOlek.IsKeyDown(Keys.Left) && !eelmineOlek.IsKeyDown(Keys.Left)
                                                     && !kujund.VasakPoordeKokkuPorge)
            {
                kujund.Asend = (kujund.Asend + 3) % 4;
            }

            // Enter viskab klotsi kohe paremale lõppu
            if (klaveriOlek.IsKeyDown(Keys.Enter) && !eelmineOlek.IsKeyDown(Keys.Enter)
                                                      && !kujund.ParemKokkuPorge)
            {
                while (kujund.ParemKokkuPorge == false)
                {
                    kujund.AsuKohaTulp += 1;
                    kujund.KokkuporgeteAvastamine(tase);
                }
                ajaHoidja = aegLiigutamiseks;            
            }

            // Üles-nool liigutab kujundit ühe rea võrra üles
            if (klaveriOlek.IsKeyDown(Keys.Up) && !eelmineOlek.IsKeyDown(Keys.Up)
                                                   && !kujund.YlalKokkuPorge)
            {
                kujund.AsuKohaRida -= 1;
                                
            }

            // Alla-nool liigutab kujundit ühe rea võrra alla
            if (klaveriOlek.IsKeyDown(Keys.Down) && !eelmineOlek.IsKeyDown(Keys.Down)
                                                     && !kujund.AllKokkuPorge)
            {
                kujund.AsuKohaRida += 1;
            }

        }

        /// <summary>
        /// Hangib sisendi puldi nuppudelt, vaatab, kas see käsk on võimalik, ja viib käsu ellu
        /// </summary>
        
        public void LiigutaKujund(GamePadState puldiOlek, GamePadState puldiEelmineOlek, Tase tase, Kujund kujund)
        {
           
            // Kõigepealt üritatakse avastada kokkupõrkeid, et teha kindlaks, milliseid klahve on üldse võimalik kasutada
            kujund.KokkuporgeteAvastamine(tase);

            // Parem "DPad" paremale liigutab kujundit paremale edasi
            if (puldiOlek.DPad.Right == ButtonState.Pressed && puldiEelmineOlek.DPad.Right != ButtonState.Pressed
                                                      && !kujund.ParemKokkuPorge)
            {
                kujund.AsuKohaTulp += 1; 
            }

            // Parem "DPad" keerab kujundit
            if (puldiOlek.DPad.Left == ButtonState.Pressed && puldiEelmineOlek.DPad.Left != ButtonState.Pressed
                                                     && !kujund.VasakPoordeKokkuPorge)
            {
                kujund.Asend = (kujund.Asend + 3) % 4;
            }

            // Vasak "trigger" viskab kujundi kohe lõppu
            if (puldiOlek.Triggers.Right > 0.5f && puldiEelmineOlek.Triggers.Right < 0.5f
                                                      && !kujund.ParemKokkuPorge)
            {
                while (kujund.ParemKokkuPorge == false)
                {
                    kujund.AsuKohaTulp += 1;
                    kujund.KokkuporgeteAvastamine(tase);
                }
                ajaHoidja = aegLiigutamiseks;                
               
            }

            // Parem "DPad" üles liigutab kujundit rea võrra üles
            if (puldiOlek.DPad.Up == ButtonState.Pressed && puldiEelmineOlek.DPad.Up == ButtonState.Pressed
                                                   && !kujund.YlalKokkuPorge)
            {
                kujund.AsuKohaRida -= 1;
                                
            }

            // Parem "DPad" alla liigutab kujundit rea võrra alla
            if (puldiOlek.DPad.Down == ButtonState.Pressed && puldiEelmineOlek.DPad.Down == ButtonState.Pressed
                                                     && !kujund.AllKokkuPorge)
            {
                kujund.AsuKohaRida += 1;
                
              }
           
        }


        /// <summary>
        /// Joonistab kõik kujundid - väljakule mineva, järgmise kujundi aknasse mineva järgmise kujundi
        /// ning juba paigasolevad kujundid
        /// </summary>
        public void JoonistaKoikKujundid(Tase tase, Kujund kujund, SpriteBatch spriteBatch, SpriteFont spriteFont)
        {           
            kujund.JoonistaKujund(spriteBatch);
            kujund.JoonistaJargmineKujund(spriteBatch);
            tase.JoonistaPaigasKujundid(spriteBatch);
        }

        /// <summary>
        /// Arvestab täis saanud tulpi ja skoori ning
        /// vajadusel viib mängija uuele tasemele
        /// </summary>
        public void UuendaManguLoogika(Tase tase, GameTime manguAeg)
        {           
            // Täidetud tulpade arv
            int taisTulpe = tase.TegeleTaisTulbaga();

            // Muudab skoori vastavalt täidetud tulpade arvule
            tase.UuendaSkoor(tase.taisTulpasid);
                        
            // Iga 10 täisrea kohta suureneb tase 1 võrra
            if (taisTulpe != 0 && !Totris.Taust.IsPaused)
                
                switch (taisTulpe)
                {
                    case 1:
                    Totris.sfxHeli.PlayCue("siuh");
                    break;

                    case 2:
                    Totris.sfxHeli.PlayCue("line");
                    break;

                    case 3:
                    Totris.sfxHeli.PlayCue("line2");
                    break;

                    case 4:
                    Totris.sfxHeli.PlayCue("line3");
                    break;
                }

            tase.UuendaTase();
        }
       
    }
}
